import Axios, {
    type AxiosInstance,
    type AxiosRequestConfig,
    type AxiosResponse,
    CanceledError,
    type CustomParamsSerializer
} from 'axios'
import type { RequestMethods } from './types.d.ts'
import { stringify } from 'qs'
import { type RequestOptions, UNKNOWN_MSG } from '@/utils/http/request'
import type Result from '@/utils/http/Result'
import { $error, $warning, message } from '@/utils/message'
import { addAbortController } from './httpRequestList'
import { h } from 'vue'
// import { clearToken, getToken } from '@/utils/auth'
// import router from '@/router'

// const TOKEN_HEADER_NAME = 'Authorization'

// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
    // 请求超时时间
    timeout: 1000 * 60 * 2,
    headers: {
        Accept: 'application/json, text/plain, */*',
        'Content-Type': 'application/json;charset=UTF-8',
        'X-Requested-With': 'XMLHttpRequest',
    },
    // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
    paramsSerializer: {
        serialize: (params: any) => stringify(params, { 
            charset: 'utf-8',
            arrayFormat: 'brackets'
        }),
    },
}

const axiosInstance: AxiosInstance = Axios.create(defaultConfig)

axiosInstance.interceptors.request.use(
    (options) => {
        // const token = getToken()
        // if (token) {
        //     options.headers[TOKEN_HEADER_NAME] = token
        // }
        return options
    },
    (error) => {
        Promise.reject(error)
    },
)

axiosInstance.interceptors.response.use(
    (response) => {
        // if (response.data.code === 4001) {
        //     clearToken()
        //     router.push({
        //         name: 'login'
        //     }).catch(() => {
        //     })
        // }
        // NProgress.done()
        return response
    },
    (error) => {
        if (!(error instanceof CanceledError)) {
            error.message = error?.response?.data?.message ?? UNKNOWN_MSG
            $warning(error.message, {grouping: true})
        }
        // NProgress.done()
        return Promise.reject(error)
    },
)

export const http = <T>(
    method: RequestMethods,
    url: string,
    params?: Record<string, any>,
    data?: Record<string, any>,
    extraConfig?: RequestOptions<any>,
) => {
    return new Promise<Result<T>>((resolve, reject) => {
        let controller = new AbortController()
        addAbortController(controller)

        const config = {
            method,
            url,
            params,
            data,
            signal: controller.signal,
            ...extraConfig,
        } as RequestOptions<any>

        return axiosInstance
            .request(config)
            .then((res: AxiosResponse) => {
                if (config.responseType === 'arraybuffer') {
                    resolve(res.data)
                } else {
                    // 状态码 2xx，参考 axios 的设计
                    if (res.status >= 200 && res.status < 300) {
                        const data: Result<T> = res.data as Result<T>
                        if (data.code !== 200) {
                            if (data.supportCode) {
                                $error(
                                    h('div', {class: 'el-message__content'}, [
                                        h('p', {class: 'pb-2'}, '发生错误，请稍后再试或刷新页面重试'),
                                        h('p', {class: 'pb-2'}, '如问题持续存在，请提供以下错误编号给技术支持，以便进一步排查'),
                                        h('p', null, `错误编号: ${data.supportCode}`),
                                    ]),
                                    {grouping: true},
                                )
                            } else if (data.code === 4001) {
                                $error('登录已失效，请重新登录', {grouping: true})
                            } else {
                                $warning(data.msg || data.message, {grouping: true})
                            }
                        }
                        resolve(data)
                    } else if (res.status === 401) {
                        reject(res)
                    } else {
                        !extraConfig.hideErrorToast && message('请求错误', {type: 'warning'}) // 其他错误 -> 根据后端错误信息轻提示
                        reject(res)
                    }
                }
            })
            .catch((error) => {
                reject(error)
            })
    })
}

/**
 * GET 请求
 * @param url 后台地址
 * @param query 请求query参数
 * @param extraConfig 额外参数，覆盖默认参数
 * @returns
 */
export const httpGet = <T>(url: string, query?: Record<string, any>, extraConfig?: RequestOptions<any>) => {
    return http<T>('get', url, query, undefined, extraConfig)
}

/**
 * POST 请求
 * @param url 后台地址
 * @param data 请求body参数
 * @param params 请求params参数，post请求也支持query，很多微信接口都需要
 * @param extraConfig 额外参数，覆盖默认参数
 * @returns
 */
export const httpPost = <T>(url: string, data?: Record<string, any>, params?: Record<string, any>, extraConfig?: RequestOptions<any>) => {
    return http<T>('post', url, params, data, extraConfig)
}

/**
 * export 请求
 * @param url 后台地址
 * @param data 请求body参数
 * @param params 请求params参数，post请求也支持query，很多微信接口都需要
 * @param extraConfig 额外参数，覆盖默认参数
 * @returns
 */
export const httpExport = <T>(url: string, data?: Record<string, any>, params?: Record<string, any>, extraConfig?: RequestOptions<any>) => {
    return http<T>('post', url, params, data, {...{responseType: 'arraybuffer'}, ...extraConfig})
}

/**
 * stream 请求
 * @param url 后台地址
 * @param data 请求body参数
 * @returns
 */
export const httpStream = (url: string, data?: unknown) => {
    return fetch(url, {
        method: 'POST',
        body: data ? JSON.stringify(data) : undefined,
        headers: {
            Accept: 'application/json, text/plain, */*',
            'Content-Type': 'application/json',
            'X-Requested-With': 'XMLHttpRequest',
        },
    })
}

export const cancelHttpRequest = () => {
    // cancelTokenSource.cancel()
}

http.get = httpGet
http.post = httpPost
http.export = httpExport
http.stream = httpStream
